package com.niiwoo.civet.account.service.local.trade;

import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.event.constant.BizEventRabbitConstant;
import com.niiwoo.activity.event.dto.request.RechargeEventReqDTO;
import com.niiwoo.activity.event.enums.RechargeTypeEventEnum;
import com.niiwoo.activity.event.enums.UserRoleTypeEventEnum;
import com.niiwoo.activity.event.enums.YesOrNoEnum;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.BankType;
import com.niiwoo.civet.account.dao.entity.PayChannel;
import com.niiwoo.civet.account.dao.entity.WithholdOrder;
import com.niiwoo.civet.account.dao.mapper.BankTypeMapperExt;
import com.niiwoo.civet.account.dao.mapper.PayChannelMapperExt;
import com.niiwoo.civet.account.dao.mapper.WithholdOrderMapperExt;
import com.niiwoo.civet.account.dto.bill.AddBillAndChangeBalanceDTO;
import com.niiwoo.civet.account.dto.bill.AddBillDetailDTO;
import com.niiwoo.civet.account.dto.request.RechargeRecordRequestDTO;
import com.niiwoo.civet.account.enums.*;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.civet.account.service.local.bill.BillFacade;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.trade.constant.MqConstant;
import com.niiwoo.civet.trade.dto.response.WithholdResultDTO;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Arrays;
import java.util.Date;
import java.util.Objects;

/**
 * 代扣Service
 * Created by xiaoyingping on 2018/4/25.
 */
@Service
@Slf4j
public class WithholdService {

    @Autowired
    private WithholdOrderService withholdOrderService;
    @Autowired
    private WithholdOrderMapperExt withholdOrderMapperExt;

    @Autowired
    private BillFacade billFacade;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private BankTypeMapperExt bankTypeMapperExt;
    @Autowired
    private PayChannelMapperExt payChannelMapperExt;
    @Autowired
    private AccountService accountService;


    /**
     * 代扣成功
     *
     * @param withholdOrderId
     */
    @Transactional
    public void processWithholdSuccess(Long withholdOrderId, OrderEndTypeEnum endType) {
        log.info("开始代扣成功后的处理，withholdOrderId:{}", withholdOrderId);
        WithholdOrder withholdOrder = withholdOrderService.selectByPrimaryKeyForUpdate(withholdOrderId);
        log.info("代扣订单当前状态是:{}", withholdOrder.getStatus());
        if (WithholdOrderStatusEnum.SUCCESS.getValue() == withholdOrder.getStatus()) {
            log.info("代扣订单当前状态是已成功，不需要再处理");
            return;
        }
        if(WithholdOrderStatusEnum.HANDLING.getValue() != withholdOrder.getStatus()){
            throw new BizException("ACC41001","代扣订单当前状态非处理中");
        }

        //修改代扣订单的状态为"成功"
        log.info("将代扣订单的状态修改为成功");
        WithholdOrder record = new WithholdOrder();
        record.setId(withholdOrderId);
        record.setStatus(WithholdOrderStatusEnum.SUCCESS.getValue());
        record.setEndType(endType.getValue());
        Date nowDate = new Date();
        record.setSuccessTime(nowDate);
        record.setEndTime(nowDate);
        record.setUpdateTime(nowDate);
        withholdOrderMapperExt.updateByPrimaryKeySelective(record);

        //变更余额 + 记账
        AddBillDetailDTO addBillDetailDTO = new AddBillDetailDTO();
        addBillDetailDTO.setAmount(withholdOrder.getAmount());
        addBillDetailDTO.setBillSecondSubjectEnum(BillSecondSubjectEnum.USER_RECHARGE);
        addBillDetailDTO.setRemark2(BillRemark3Enum.RECHARGE_TREATY_TYPE.getDesc());

        AddBillAndChangeBalanceDTO billDTO = new AddBillAndChangeBalanceDTO();
        billDTO.setAccountId(withholdOrder.getAccountId());
        billDTO.setAmount(withholdOrder.getAmount());
        billDTO.setInoutType(InoutTypeEnum.IN_TYPE);
        billDTO.setOrderId(withholdOrder.getOrderId());
        billDTO.setOrderType(OrderTypeEnum.RECHARGE_AUTO);
        billDTO.setRequestNo(withholdOrder.getRequestNo());
        billDTO.setStatus(BillStatusEnum.SUCCESS);
        billDTO.setChannelCode(ChannelCodeEnum.APP);
        billDTO.setAddBillDetailDTOList(Arrays.asList(addBillDetailDTO));
        billFacade.addBillAndChangeBalance(billDTO);

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                super.afterCommit();

                try {
                    //发送代扣结果通知MQ
                    WithholdResultDTO withholdResultDTO = new WithholdResultDTO();
                    withholdResultDTO.setOrderId(withholdOrder.getOrderId());
                    withholdResultDTO.setCode("0000");
                    sendWithholdResultNotifyMq(withholdResultDTO);

                    //发送充值事件通知MQ
                    sendRechargeEventMq(withholdOrder);
                }catch (Exception e){
                    log.error("发送代扣结果通知MQ失败{}",JSON.toJSONString(withholdOrder),e);
                }

            }
        });


    }

    /**
     * 代扣失败
     *
     * @param withholdOrderId
     * @param errorCode
     * @param errorMsg
     */
    @Transactional
    public void processWithholdFail(Long withholdOrderId, String errorCode, String errorMsg, OrderEndTypeEnum endType) {
        log.info("开始代扣失败后的处理,withholdOrderId:{}", withholdOrderId);
        WithholdOrder withholdOrder = withholdOrderService.selectByPrimaryKeyForUpdate(withholdOrderId);
        log.info("代扣订单当前状态是:{}", withholdOrder.getStatus());
        if (WithholdOrderStatusEnum.FAIL.getValue() == withholdOrder.getStatus()) {
            log.info("代扣订单当前状态是已失败，不需要再处理");
            return;
        }
        if(WithholdOrderStatusEnum.HANDLING.getValue() != withholdOrder.getStatus()){
            throw new BizException("ACC41001","代扣订单当前状态非处理中");
        }

        //修改代扣订单的状态为"失败"
        log.info("将代扣订单的状态修改为失败");
        WithholdOrder record = new WithholdOrder();
        record.setId(withholdOrderId);
        record.setStatus(WithholdOrderStatusEnum.FAIL.getValue());
        record.setErrorCode(errorCode);
        record.setErrorMessage(errorMsg);
        record.setEndType(endType.getValue());
        Date nowDate = new Date();
        record.setUpdateTime(nowDate);
        record.setEndTime(nowDate);
        withholdOrderMapperExt.updateByPrimaryKeySelective(record);

        //发送代扣结果通知MQ
        WithholdResultDTO withholdResultDTO = new WithholdResultDTO();
        withholdResultDTO.setOrderId(withholdOrder.getOrderId());
        withholdResultDTO.setCode(errorCode);
        withholdResultDTO.setMessage(errorMsg);
        this.sendWithholdResultNotifyMq(withholdResultDTO);
    }


    //发送代扣结果通知到MQ
    public void sendWithholdResultNotifyMq(WithholdResultDTO withholdResultDTO) {
        try {
            log.info("发送代扣结果通知MQ:{}", JSON.toJSONString(withholdResultDTO));
          rabbitTemplate.convertAndSend(MqConstant.WITHHOLD_APPLY_EXCHANGE, MqConstant.WITHHOLD_APPLY_DATAREULST_ROUTING, withholdResultDTO);
        } catch (AmqpException e) {
            log.error("发送代扣结果通知MQ发生异常:", e);
        }
    }


    //发送代扣事件的消息通知
    private void sendRechargeEventMq(WithholdOrder withholdOrder) {
        AccountBase accountBase = accountService.loadAccountById(withholdOrder.getAccountId());

        RechargeEventReqDTO rechargeEventReqDTO = new RechargeEventReqDTO();
        rechargeEventReqDTO.setRechargeId(withholdOrder.getId());
        rechargeEventReqDTO.setUserId(withholdOrder.getUserId());
        rechargeEventReqDTO.setUpdateDate(new Date());
        rechargeEventReqDTO.setAmount(withholdOrder.getAmount());
        rechargeEventReqDTO.setBankCode(withholdOrder.getBankCode());

        if(Objects.nonNull(withholdOrder.getPayChannelId())) {
            PayChannel payChannel = payChannelMapperExt.selectByPrimaryKey(withholdOrder.getPayChannelId());
            rechargeEventReqDTO.setPayChannelName(payChannel.getChannelName());
        }else {
            rechargeEventReqDTO.setPayChannelName(null);
        }

        if(Objects.nonNull(withholdOrder.getBankCardId())) {
            BankType bankType = bankTypeMapperExt.selectBankTypeByCode(withholdOrder.getBankCode());
            rechargeEventReqDTO.setBankName(bankType.getBankName());
        }else {
            rechargeEventReqDTO.setBankName(null);
        }

        rechargeEventReqDTO.setRechargeDate(withholdOrder.getCreateTime());
        rechargeEventReqDTO.setRechargeTypeEventEnum(RechargeTypeEventEnum.withhold);
        rechargeEventReqDTO.setUserRoleTypeEventEnum(UserRoleTypeEventEnum.valueOf(accountBase.getAccountRole()));
        RechargeRecordRequestDTO requestDTO = new RechargeRecordRequestDTO();
        requestDTO.setUserId(withholdOrder.getUserId());
        requestDTO.setStatus(withholdOrder.getStatus());
        rechargeEventReqDTO.setFirstRechargeYesOrNoEnum(YesOrNoEnum.NO);

        try {
            log.info("发送代扣事件的消息通知MQ:{}", JSON.toJSONString(rechargeEventReqDTO));
            rabbitTemplate.convertAndSend(BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE, BizEventRabbitConstant.Key.BIZ_EVENT_RECHARGE_KEY, rechargeEventReqDTO);
        } catch (AmqpException e) {
            log.error("发送代扣事件的消息通知发生异常:{}", e);
        }
    }





}
